package paim.wingchun.model.pojos;


import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import javax.persistence.Column;
import javax.persistence.GeneratorType;
import javax.persistence.Id;
import javax.persistence.Transient;
import javax.persistence.Version;

import org.hibernate.Hibernate;

import paim.wingchun.app.WC_Utils;

/** Plain Old Java Objects */
@org.hibernate.annotations.Entity
@javax.persistence.EmbeddableSuperclass
public abstract class Pojo implements Serializable, Comparable<Pojo>, Cloneable {

    private static final long serialVersionUID = 1L;

    @Id(generate = GeneratorType.IDENTITY)
    @Column(nullable = false)
    protected Long id;

    @Version
    @Column(nullable = false)
    protected Integer versao;

    @Column(nullable = false)
    private Integer pendencia = 0;

    protected transient List<Erro> erros = new ArrayList<Erro>();

    /** indica que o objeto foi altera pelo usuario */
    private transient boolean alterado = false;

    public Pojo() {
        super();
    }

    @Id(generate = GeneratorType.IDENTITY)
    @Column(nullable = false)
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @Version
    @Column(nullable = false)
    public Integer getVersao() {
        return versao;
    }

    public void setVersao(Integer versao) {
        this.versao = versao;
    }

    public Integer getPendencia() {
        return pendencia;
    }

    public void setPendencia(Integer pendencia) {
        this.pendencia = pendencia;
    }

    @Transient
    public List<Erro> getErros() {
        return erros;
    }

    public void setErros(List<Erro> erros) {
        this.erros = erros;
    }

    @Transient
    public boolean getAlterado() {
        return alterado;
    }

    public void setAlterado(boolean alterado) {
        this.alterado = alterado;
    }

    @Override
    public int compareTo(Pojo o) {
        if ( this.getId() == null && o.getId() == null )
            return 0;

        if ( this.getId() == null && o.getId() != null )
            return -1;

        if ( this.getId() != null && o.getId() == null )
            return 1;

        return (int) (this.getId() - o.getId());
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 7;
        result = prime * result + Hibernate.getClass(this).getSimpleName().hashCode();

        /* XXX cuidado com esse hash, pois ao salvar o hash vai mudar conforme abaixo */
        /* se mudar, cuidado com maps e sets */
        if ( this.id == null )
            result = super.hashCode();
        else {
            result = prime * result + this.id.hashCode();
        }
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if ( this == obj )
            return true;

        /* nao esta levando em conta colecoes..... */
        if ( obj == null )
            return false;

        if ( Hibernate.getClass(this) != Hibernate.getClass(obj) )
            return false;

        final Pojo other = (Pojo) obj;

        if ( Objects.equals(this.id, other.id) )
            return false;
        if ( Objects.equals(this.pendencia, other.pendencia) )
            return false;
        if ( Objects.equals(this.versao, other.versao) )
            return false;

        return true;
    }

    @Override
    public String toString() {
        String str = getClass().getSimpleName() + ": {";
        str += this.getId();
        str += "}";
        return str;
    }

    /** verifica se dois pojos sao iguais<BR>
     * leva em conta o id bancom classe e null
     *
     * @author paim 14/12/2011
     * @param esse
     * @param outro
     * @return boolean */
    public static boolean equals(Pojo esse, Pojo outro) {
        if ( esse == null && outro == null )
            return true;

        if ( esse != null && outro != null && esse.getClass() == outro.getClass()
                        && Objects.equals(esse.getId(), outro.getId()) )
            return true;

        return false;
    }

    /** nao se se esse metodo deveria estar no model? */
    /* usando java8 lambda */
//    @javax.persistence.Transient
//@java.beans.Transient
    public static List<Long> ids(List<? extends Pojo> pojos) {
        /* nao sei porque , mas se eu colocar o codigo que esta em WC_Utils.ids aqui da erro ao instanciar hibernate,
         * talvez deva atualizar tudo */
    
        //return pojos.stream().map(o -> o.getId()).collect(Collectors.toList());
        return WC_Utils.ids(pojos);

        // Exception in thread "main" java.lang.reflect.GenericSignatureFormatError: Signature Parse error: expected ')'
        // Remaining input: +Lpaim/wingchun/model/pojos/Pojo;)Ljava/lang/Long;
        // at sun.reflect.generics.parser.SignatureParser.error(SignatureParser.java:124)
        // at sun.reflect.generics.parser.SignatureParser.parseFormalParameters(SignatureParser.java:586)
        // at sun.reflect.generics.parser.SignatureParser.parseMethodTypeSignature(SignatureParser.java:576)
        // at sun.reflect.generics.parser.SignatureParser.parseMethodSig(SignatureParser.java:171)
        // at sun.reflect.generics.repository.ConstructorRepository.parse(ConstructorRepository.java:55)
        // at sun.reflect.generics.repository.ConstructorRepository.parse(ConstructorRepository.java:43)
        // at sun.reflect.generics.repository.AbstractRepository.<init>(AbstractRepository.java:74)
        // at sun.reflect.generics.repository.GenericDeclRepository.<init>(GenericDeclRepository.java:48)
        // at sun.reflect.generics.repository.ConstructorRepository.<init>(ConstructorRepository.java:51)
        // at sun.reflect.generics.repository.MethodRepository.<init>(MethodRepository.java:46)
        // at sun.reflect.generics.repository.MethodRepository.make(MethodRepository.java:59)
        // at java.lang.reflect.Method.getGenericInfo(Method.java:99)
        // at java.lang.reflect.Method.getGenericReturnType(Method.java:241)
        // at org.hibernate.cfg.PropertyInferredData.findCollectionType(PropertyInferredData.java:132)
        // at org.hibernate.cfg.PropertyInferredData.execute(PropertyInferredData.java:103)
        // at org.hibernate.cfg.PropertyInferredData.skip(PropertyInferredData.java:53)
        // at org.hibernate.cfg.AnnotationBinder.addAnnotatedElement(AnnotationBinder.java:825)
        // at org.hibernate.cfg.AnnotationBinder.addElementsOfAClass(AnnotationBinder.java:802)
        // at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:638)
        // at org.hibernate.cfg.AnnotationConfiguration.processArtifactsOfType(AnnotationConfiguration.java:256)
        // at org.hibernate.cfg.AnnotationConfiguration.secondPassCompile(AnnotationConfiguration.java:191)
        // at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1138)
        // at paim.wingchun.app.Hibernates.<init>(Hibernates.java:73)
        // at paim.wingchun.app.Hibernates.<init>(Hibernates.java:32)
        // at paim.wingchun.app.Hibernates.<init>(Hibernates.java:27)
        // at paim.wingchun.app.WC_App.initializeHibernate(WC_App.java:452)
        // at paim.wingchun.app.WC_App.<init>(WC_App.java:129)
        // at paim.gh.app.GHApp.<init>(GHApp.java:22)
        // at paim.gh.app.GHApp.main(GHApp.java:72)

    }
}
